import inquirer from 'inquirer'
import fs from 'fs'
import crypto from 'crypto'

async function main() {
  // if you want to add new env variables, add them here
  const answers = await inquirer
    .prompt([
      {
        name: 'DEV_ENV',
        type: 'confirm',
        message: 'Is this local-dev environment?',
        default: false,
      },
      {
        name: 'REDIS_HOST',
        message: 'Redis host',
        type: 'input',
        default: 'redis',
      },
      {
        name: 'REDIS_PORT',
        message: 'Redis port',
        type: 'number',
        default: 6379,
      },
      {
        name: 'POSTGRES_DATABASE',
        message: 'Postgres database',
        type: 'input',
        default: 'boticord',
      },
      {
        name: 'POSTGRES_PORT',
        message: 'Postgres port',
        type: 'number',
        default: 5432,
      },
      {
        name: 'POSTGRES_PASSWORD',
        message: 'Postgres password',
        type: 'input',
        default: '123',
      },
      {
        name: 'POSTGRES_USERNAME',
        message: 'Postgres username',
        type: 'input',
        default: 'postgres',
      },
      {
        name: 'POSTGRES_HOST',
        message: 'Postgres host',
        default: 'postgres',
      },
      {
        name: 'NATS_SERVERS',
        type: 'input',
        default: 'nats://nats:4222',
        message: 'Enter NATS servers (separate with a comma)',
      },
      {
        name: 'DISCORD_CLIENT_ID',
        message: 'Discord OAuth2 client ID',
        validate: i => !!i,
        type: 'input',
      },
      {
        name: 'DISCORD_CLIENT_SECRET',
        message: 'Discord OAuth2 client secret',
        validate: i => !!i,
        type: 'input',
      },
      {
        name: 'DISCORD_SCOPES',
        message: 'Discord OAuth2 scopes',
        type: 'input',
        default: 'identify guilds',
      },
      {
        name: 'DISCORD_TOKEN',
        message: 'Discord bot token',
        validate: i => !!i,
        type: 'input',
      },
      {
        name: 'DISCORD_WEBHOOK_CDN_TOKEN',
        message: 'Discord webhook token (used for cdn)',
        validate: i => !!i,
        type: 'input',
      },
      {
        name: 'DISCORD_WEBHOOK_CDN_ID',
        message: 'Discord webhook id (used for cdn)',
        validate: i => !!i,
        type: 'input',
      },
      {
        name: 'APP_PORT',
        message: 'Application port',
        type: 'input',
        default: 3000,
      },
      {
        name: 'APP_HOST',
        message: 'Application host',
        type: 'input',
        default: '0.0.0.0',
      },
      {
        name: 'MEILISEARCH_HOST',
        message: 'Meilisearch access point',
        type: 'input',
        default: 'http://meili:7700/',
      },
      {
        name: 'NODE_ENV',
        message: 'Execution Environment',
        choices: [ 'development', 'production' ],
        type: 'list',
        default: 'development',
      },
      {
        name: 'ADMINER_HOST',
        message: 'Adminer host',
        default: 'adminer.local',
      },
      {
        name: 'API_HOST',
        message: 'API host',
        default: 'api.local',
      },
      {
        name: 'GATEWAY_HOST',
        message: 'Gateway host',
        default: 'gateway.local',
      },
      {
        name: 'CDN_HOST',
        message: 'CDN host',
        default: 'cdn.local',
      },
      {
        name: 'NGINX_PORT',
        message: 'Nginx port',
        type: 'number',
        default: 80,
        validate: i => !!i,
      },
      {
        name: 'OWNER_IDS',
        message: 'Discord ID of the bot owners, separated by commas',
        type: 'input',
        default: 'nobody',
      },
      {
        name: 'BOT_PREFIX',
        message: 'Bot prefix',
        type: 'input',
        validate: i => !!i,
      },
      {
        name: 'QUEUE_SERVER',
        message: 'ID for queue server',
        type: 'input',
        validate: i => !!i,
      },
      {
        name: 'WORKER_BOT_FETCH_ENDPOINT',
        message: 'Cloudflare worker for bot fetch endpoint (optional) (example: https://work.a.workers.dev/bot/)',
        type: 'input',
      },
      {
        name: 'CF_ACCESS_BOT_FETCH_CLIENT_ID',
        message: 'Cloudflare access for bot fetch client id (optional when cloudflare access is disabled)',
        type: 'input',
      },
      {
        name: 'CF_ACCESS_BOT_FETCH_CLIENT_SECRET',
        message: 'Cloudflare access for bot fetch client secret (optional when cloudflare access is disabled)',
        type: 'input',
      },
      {
        name: 'WORKER_NOTIFY_ENDPOINT',
        message: 'Cloudflare worker for notifications endpoint (example: https://work.a.workers.dev/notify/)',
        type: 'input',
        validate: i => !!i,
      },
      {
        name: 'CF_ACCESS_NOTIFY_CLIENT_ID',
        message: 'Cloudflare access for notifications client id (optional when cloudflare access is disabled)',
        type: 'input',
      },
      {
        name: 'CF_ACCESS_NOTIFY_CLIENT_SECRET',
        message: 'Cloudflare access for notifications client secret (optional when cloudflare access is disabled)',
        type: 'input',
      },
      {
        name: 'WORKER_MON_CHECK_ENDPOINT',
        message: 'Cloudflare worker for checking bot publicity in other monitoring-s (step 4 bot adding)',
        type: 'input',
        validate: i => !!i,
      },
      {
        name: 'CF_ACCESS_MON_CHECK_CLIENT_ID',
        message: 'Cloudflare access for monitoring check: client id (optional when cloudflare access is disabled)',
        type: 'input',
      },
      {
        name: 'CF_ACCESS_MON_CHECK_CLIENT_SECRET',
        message: 'Cloudflare access for monitoring check: client secret (optional when cloudflare access is disabled)',
        type: 'input',
      },
      {
        name: 'TURNSTILE_SECRET',
        message: 'Cloudflare Turnstile (captcha) website secret',
        type: 'input',
        validate: i => !!i,
      },
      {
        name: 'GENERATE_SECRETS',
        message: 'Would you like to generate secrets?',
        type: 'confirm',
        default: true,
      },
    ])
    .catch(error => {
      if (error.isTtyError) {
        console.error('your environment does not support this script')
      } else {
        console.error(error)
      }
    })

  const isLocal = answers.DEV_ENV
  const envPath = isLocal ? './.env-dev' : './.env'

  const now = (Date.now() / 1000).toFixed()
  if (fs.existsSync(envPath)) {
    const ne = `${envPath}.${now}.bak`
    fs.renameSync(envPath, ne)

    console.log(`Moved existing ${envPath} file to ${ne}`)
  }

  const file: string[] = []
  const generateSecrets = answers.GENERATE_SECRETS
  delete answers['GENERATE_SECRETS']

  answers.MEILI_ENV = answers.NODE_ENV
  answers.MEILI_NO_ANALYTICS = 'yes'

  if (generateSecrets) {
    console.log(
      'WARNING: you\'ve chosen to generate secrets.',
      'Keep in mind that this will invalidate all old sessions.',
      `You can find old secrets in ${envPath}.bak file.`,
    )
    answers.JWT_SECRET = crypto.randomBytes(32).toString('hex')
    answers.AUTH_ENCRYPTION_SECRET = crypto.randomBytes(32).toString('hex')
    answers.AUTH_IV_SECRET = crypto.randomBytes(16).toString('hex')
    answers.MEILI_MASTER_KEY = crypto.randomBytes(32).toString('hex')
    answers.CF_ANALYTICS_SECRET = crypto.randomBytes(8).toString('hex')
    console.log('Cloudflare Analytics secret, pass into cloudflare worker:', answers.CF_ANALYTICS_SECRET)
    answers.RPC_SECRET = crypto.randomBytes(8).toString('hex')
  } else {
    console.log(
      'Please generate JWT_SECRET,',
      'AUTH_ENCRYPTION_SECRET,',
      'AUTH_IV_SECRET,',
      'MEILI_MASTER_KEY,',
      'CF_ANALYTICS_SECRET,',
      'RPC_SECRET',
      'manually and add them to', envPath,
    )
  }

  file.push('# AUTOGENERATED. USE npm run configure TO RECONFIGURE')
  file.push('# GENERATION TIMESTAMP:', now)
  for (const key in answers) {
    file.push(`${key}=${answers[key]}`)
  }

  fs.writeFileSync(envPath, file.join('\n'))

  console.log(`Configuration saved to ${envPath}`)
}

main()